﻿using iS3.DAL;
using iS3.DAL.Table;
using iS3.Server.Core.Core;
using iS3.Server.Core.Util;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace iS3.Server.Core
{
    public  class Repository<T> : IRepository<T> where T : DGBase,new()
    {
        public IDataContext<T> context;
        public WebRequestContext webcontext;
        public string prj;
        public string _type;
        public string _connectionStr;
        public Repository(string prj, WebRequestContext _webcontext,string type=null)
        {
            this.prj = prj;
            this.webcontext = _webcontext;

            this._type = type;
            //获取项目的连接信息
            this._connectionStr = PrjManager.getConnectionStr(prj, _webcontext); 
            this.initDBContext(this._connectionStr);
        }
        public virtual void initDBContext(string connectionStr)
        {
            context = DataContextFactory.GetDataContext<T>(connectionStr);
        }
        public virtual DGEntityStruct GetDesc()
        {
            return DGEntityManager.GetInstance().GetStruct(typeof(T));
        }

        public  virtual List<T> BatchCreate(List<T> models, string dataset = null)
        {
            //get the define of dataset
            ExternalStorageConfig config = null;
            if (dataset!=null)
            {
                config = getDatasetDefine(dataset);
            }
            
            if (typeof(T).IsSubclassOf(typeof(DGEntity)))
            {
                List<T> res = new List<T>();

                List<long> ids = ID_Gen.GetIdList(models.Count, webcontext);

                for (int i = 0; i < models.Count; i++)
                {
                    T model = models[i];
                    DGEntity entity = model as DGEntity;
                    //modify: set id
                    entity.ID = entity.ID>0? entity.ID: ids[i];   //如果自带id，则自带

                    entity.SYS_DataTime = DateTime.Now;
                    entity.SYS_DataSet = dataset;
                    entity.SYS_DataState = true;
                    res.Add(entity as T);
                }
                return context.BatchCreate(res, config);
            }
            else
            {
                return context.BatchCreate(models, config);
            }
        }

        public virtual int BatchDelete(List<long> ids,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.BatchDelete(ids, config);
        }

        public virtual T Create(T model, string dataset = null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }

            if (typeof(T).IsSubclassOf(typeof(DGEntity)))
            {
                long id = ID_Gen.GetId(webcontext);

                DGEntity entity = model as DGEntity;
                //modify
                entity.ID = entity.ID > 0 ? entity.ID : ID_Gen.GetId(webcontext);
                entity.SYS_DataTime = DateTime.Now;
                entity.SYS_DataState = true;
                entity.SYS_DataSet = dataset;
                return context.Create(entity as T, config);
            }
            else
            {
                return context.Create(model, config);
            }
          
        }

        public virtual int Delete(long id,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }

            if (typeof(T).IsSubclassOf(typeof( DGEntity)))
            {
                DGEntity entity = new T() as DGEntity;
                entity.ID = id;
                entity.SYS_DataState = false;
                context.Update(entity as T, "SYS_DataState",config);
                return 1;
            }
            else
            {
                return context.Delete(id,config);
            }
        }

        public virtual T Retrieve(long id,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.Retrieve(id, config);
        }

        public virtual T Update(T model,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.Update(model, config);
        }
        public T Update(T model, string propertyName,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.Update(model, propertyName, config);
        }

        public T Update(T model, List<string> propertyNames,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.Update(model, propertyNames, config);
        }
        public virtual List<T> BatchUpdate(List<T> models,string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.BatchUpdate(models, config);
        }
        public virtual bool InitTable(string dataset=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            return context.InitTable(config);
        }

        public virtual List<T> RetrieveByPage(int pageSize, int currentPage, string orderProperty="ID", bool increase=true, string dataset = null, WhereOption option = null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }

            string whereSQL = null;
            if (typeof(T).IsSubclassOf(typeof(DGEntity)))
            {
                if ((dataset != null))
                {
                    whereSQL = option == null ? string.Format("(([SYS_DataState]='True') and ([SYS_DataSet]='{0}') )", dataset) :
                          string.Format("(([SYS_DataState]='True') and ([SYS_DataSet]='{0}') and {1})", dataset, option.where);
                }
                else
                {
                    whereSQL = option == null ? string.Format("([SYS_DataState]='True')", dataset) :
                        string.Format("(([SYS_DataState]='True') and {1})", dataset, option.where);
                }
            }
            string order = increase ? string.Format(" {0} ASC ", orderProperty) : string.Format(" {0} DESC ", orderProperty);
            return context.QueryByPage(pageSize, currentPage, order, whereSQL, config);
        }

        public virtual  List<T> RetrieveList( string dataset=null,string order="ID",bool increase=true, WhereOption option = null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }

            string whereSQL = null;
            if (typeof(T).IsSubclassOf(typeof(DGEntity)))
            {
               
                if ((dataset != null))
                {
                    whereSQL = option==null? string.Format("(([SYS_DataState]='True') and ([SYS_DataSet]='{0}') )", dataset):
                         string.Format("(([SYS_DataState]='True') and ([SYS_DataSet]='{0}') and {1})", dataset,option.where);
                }
                else
                {
                    whereSQL =option==null? string.Format("([SYS_DataState]='True')", dataset):
                        string.Format("(([SYS_DataState]='True') and {1})", dataset,option.where);
                }

            }
            string orderSQL = increase ? string.Format(" {0} ASC ", order) : string.Format(" {0} DESC ", order);
            return context.Query(whereSQL, orderSQL,config);
        }

        public virtual int DeleteRange(string dataset = null,WhereOption option = null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }

            string whereSQL = null;
            if (typeof(T).IsSubclassOf(typeof(DGEntity)))
            {

                if ((dataset != null))
                {
                    whereSQL = option == null ? string.Format("(([SYS_DataState]='True') and ([SYS_DataSet]='{0}') )", dataset) :
                         string.Format("(([SYS_DataState]='True') and ([SYS_DataSet]='{0}') and {1})", dataset, option.where);
                }
                else
                {
                    whereSQL = option == null ? string.Format("([SYS_DataState]='True')", dataset) :
                        string.Format("(([SYS_DataState]='True') and {1})", dataset, option.where);
                }

            }
            return context.DeleteRange(whereSQL, config);
        }

        public virtual int Count(string dataset=null,WhereOption option=null)
        {
            ExternalStorageConfig config = null;
            if (dataset != null)
            {
                config = getDatasetDefine(dataset);
            }
            string where = null;
            if (dataset != null)
            {
                if ((option != null)&&(option.where!=null))
                {
                    where = string.Format("(([SYS_DataSet]={0}) and ([SYS_DataState]='True') and({1}))", dataset, option.where);
                }
                else
                {
                    where = string.Format("(([SYS_DataSet]={0}) and([SYS_DataState] = 'True'))", dataset);
                }
            }
            else
            {
                if ((option != null) && (option.where != null))
                {
                    where = option.where;
                }
            }
            return context.Count(where,config);
        }

        public T AppendFile(long id, string fileIds,string dataset=null)
        {
            //先查询
            DGEntity model = Retrieve(id, dataset) as DGEntity;
            List<string> idList = new List<string>();
            if (fileIds != null)
            {
                idList = fileIds.Split(',').ToList();
            }
            List<string> oldIdList = new List<string>();
            if ((model.SYS_DataFile != null)&&(model.SYS_DataFile.Length>0))
            {
                oldIdList = model.SYS_DataFile.Split(',').ToList();
            }
            
            foreach (string _id in idList)
            {
                if ((_id.Length>0)&&(!oldIdList.Contains(_id)))
                {
                    oldIdList.Add(_id);
                }
            }
            //修改
            model.SYS_DataFile =string.Join(",", oldIdList.ToArray());
            T res = Update(model as T, "SYS_DataFile", dataset);


            //修改dataset 父级统计器
            if (dataset != null)
            {
                try
                {
                    //初始化dataset的存储环境
                    //--调用到对应的微服务组件，并调用数据初始化服务
                    webcontext.SetBaseURL(ConsulManager.ocelot);
                    webcontext.Put("",string.Format("api/prj/dataset/{0}/file?prj={1}&fileIds={2}", dataset, prj, fileIds));
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        
            return res;
        }
        public T RemoveFile(long id,string fileIds, string dataset = null)
        {

            //先查询
            DGEntity model = Retrieve(id, dataset) as DGEntity;
            List<string> idList = new List<string>();
            if (fileIds != null)
            {
                idList = fileIds.Split(',').ToList();
            }
            List<string> oldIdList = new List<string>();
            if ((model.SYS_DataFile != null) && (model.SYS_DataFile.Length > 0))
            {
                oldIdList = model.SYS_DataFile.Split(',').ToList();
            }
            List<string> newIdList = new List<string>();
            foreach (string _id in oldIdList)
            {
                if ((_id.Length > 0) && (idList.Contains(_id)))
                {

                }
                else
                {
                    newIdList.Add(_id);
                }
            }
            //修改
            model.SYS_DataFile = string.Join(",", newIdList.ToArray());
            T res  = Update(model as T, "SYS_DataFile", dataset);
            //修改dataset 父级统计器
            if (dataset != null)
            {
                try
                {
                    //初始化dataset的存储环境
                    //--调用到对应的微服务组件，并调用数据初始化服务
                    webcontext.SetBaseURL(ConsulManager.ocelot);
                    webcontext.Delete("", string.Format("api/prj/dataset/{0}/file?prj={1}&fileIds={2}", dataset, prj, fileIds));
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            //删除file表中的记录
            webcontext.SetBaseURL(ConsulManager.ocelot);
            webcontext.Delete("", string.Format("api/file/fileinformation?prj={0}&fileIds={1}", prj, fileIds));

            return res;
        }

        public ExternalStorageConfig getDatasetDefine(string datasetid)
        { 
            webcontext.SetBaseURL(ConfigurationManager.AppSettings["OcelotPath"]);
            string res = webcontext.Get("api/prj/externalconfig/" + datasetid+"?prj=" + prj).ToString();
            return Newtonsoft.Json.JsonConvert.DeserializeObject<ExternalStorageConfig>(res);
        }
    }
}
public class WhereOption
{
    public string where { get; set; }
}